#pragma once
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>

#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

using std::cout;
using std::cin;
using std::endl;



//先给tcp_server的声明: 否则Thread_Data里不认识tcp_server* _ptsvr;
class tcp_server;
struct Thread_Data
{
    Thread_Data(int new_socket, std::string client_ip, uint16_t client_port, tcp_server* ptsvr)
        :_new_socket(new_socket)
        ,_client_ip(client_ip)
        ,_client_port(client_port)
        ,_ptsvr(ptsvr)
    {}

    int _new_socket;
    std::string _client_ip;
    uint16_t _client_port;
    tcp_server* _ptsvr;
};

class tcp_server
{
private:
    int _sockfd;
    uint16_t _port = 8080;
    Log log;        
public:
    tcp_server(){}
    ~tcp_server(){}

    //1.预备
    //创建套接字 + bind + listen
    void Init();    

    //获取全连接 + 提供服务
    void Run();     

    //2.服务
    // void Service1(int newsocket, const std::string& ip, const uint16_t& port);
    //线程执行的函数
    //static void* Thread_Service(void* args);

};

////////////////////////////////part1////////////////////////////////
void tcp_server::Init()
{
    //创建套接字
    _sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(_sockfd < 0){ log(Fatal, "create socket fail "); exit(1); }
    log(Info, "create socket success ");

    //设置服务器信息
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(_port);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    bind(_sockfd,(sockaddr*)&server, sizeof(server));

    //监听连接(半连接--只管获取连接)
    listen(_sockfd, 5);
}


void tcp_server::Run()
{
    while(1)
    {   
        //1.1获取新连接(全连接--提供IO服务--可以有多个), 通过accept拿到客户端的信息
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int new_socket = accept(_sockfd, (struct sockaddr*)&client, &len);

        //1.2提取处客户端信息
        char client_ip[32];
        inet_ntop(AF_INET, &(client.sin_addr), client_ip, sizeof(client_ip));
        uint16_t client_port = ntohs(client.sin_port);
        log(Info, "get a new link... sockfd: %d, client_ip: %s, client_port: %d", _sockfd, client_ip, client_port);

        //2.1线程池
        //构建任务--push进线程池--让线程去处理这些任务
        Task t(new_socket, client_ip, client_port);
        ThreadPool<Task>* tp = ThreadPool<Task>::GetInstance();
        tp->Push(t);
    }
}


////////////////////////////////part2////////////////////////////////
//获取连接时客户端退出怎么办?服务端读取的个数为0
// void tcp_server:: Service1(int newsocket, const std::string& ip, const uint16_t& port)
// {
//     char buffer[4096];
//     while(1)
//     {
//         //读取客户端信息
//         ssize_t n = read(newsocket, buffer, sizeof(buffer));
//         if(n > 0)
//         {
//             buffer[n] = 0;
//             cout << "client: "<< buffer << endl;
//             std::string message = "server: ";
//             message += buffer;
//             write(newsocket, message.c_str(), message.size());
//         }
//         //客户端退出
//         else if(n == 0)
//         {
//             log(Info, "%s : %d quit, server close sockfd: %d", ip.c_str(), port, newsocket);
//             break;
//         }
//         //出错
//         else
//         {
//             log(Info, "read error");
//             break;
//         }
//     }
// }



////////////////////////////////////////////////-------tcp1v1-------////////////////////////////////////////////////
//1.0单线程版本
// void tcp_server::Run()
// {
//     while(1)
//     {   
//         //1.1获取新连接(全连接--提供IO服务--可以有多个), 通过accept拿到客户端的信息
//         struct sockaddr_in client;
//         socklen_t len = sizeof(client);
//         int new_socket = accept(_sockfd, (struct sockaddr*)&client, &len);

//         //1.2提取处客户端信息
//         char client_ip[32];
//         inet_ntop(AF_INET, &(client.sin_addr), client_ip, sizeof(client_ip));
//         uint16_t client_port = ntohs(client.sin_port);
//         log(Info, "get a new link... sockfd: %d, client_ip: %s, client_port: %d", _sockfd, client_ip, client_port);

//         //2.1根据连接进行通信
//         Service1(new_socket, client_ip, client_port);
//         close(new_socket);
//     }
// }

////////////////////////////////////////////////-------tcp1vn-------////////////////////////////////////////////////
//2.0多进程版本
//缺点: 不能处理太多的连接(来一个连接创一个进程--太消耗资源)
// void tcp_server::Run()
// {
//     while(1)
//     {   
//         //1.1获取新连接(全连接--提供IO服务--可以有多个), 通过accept拿到客户端的信息
//         //1.2提取处客户端信息
//         //2.1孙子进程处理数据
//         pid_t id = fork();
//         if(id == 0)
//         {
//             //child
//             close(_sockfd);
//             if(fork() > 0)exit(0);//子进程退出, 交给孙子进程处理(孤儿进程--系统自己会领养--外部的父进程就不会阻塞等待了)

//             Service1(new_socket, client_ip, client_port);
//             close(new_socket);
//             exit(0);
//         }
//         //father
//         close(new_socket);
//         pid_t rid = waitpid(id, nullptr, 0);//子进程一fork就退出, 父进程不会阻塞
//     }
// }


////////////////////////////////////////////////-------tcp1vn-------////////////////////////////////////////////////
//3.0多线程版本
//创建线程来执行任务--线程执行的函数
//线程要获取new_soket, client_ip, client_port然后调用tcp中的Service1

//细节
//1.为了能并发: 线程先自己分离
//2.static成员函数无法访问类内的成员--所以通过线程函数里的args传递(封装一个Thread_Data(有socket, ip, port, tcp_server) 传给线程函数)

//优点: 线程占的资源比较少
//缺点: 连接来了才创建线程--效率低, 不想提供长服务, 需要限制一下线程个数

// struct Thread_Data
// {
//     Thread_Data(int new_socket, std::string client_ip, uint16_t client_port, tcp_server* ptsvr)
//         :_new_socket(new_socket)
//         ,_client_ip(client_ip)
//         ,_client_port(client_port)
//         ,_ptsvr(ptsvr)
//     {}
//
//     int _new_socket;
//     std::string _client_ip;
//     uint16_t _client_port;
//     tcp_server* _ptsvr;
// };

// void tcp_server::Run()
// {
//     while(1)
//     {   
//         //1.1获取新连接(全连接--提供IO服务--可以有多个), 通过accept拿到客户端的信息
//         //1.2提取处客户端信息
//         //2.1线程处理数据
//         Thread_Data* td = new Thread_Data(new_socket, client_ip, client_port, this);
//         pthread_t tid;
//         pthread_create(&tid, nullptr, Thread_Service, td);
//     }
// }

// //多线程执行的函数
// void* tcp_server::Thread_Service(void* args)
// {
//     //分离  
//     pthread_detach(pthread_self());
//     Thread_Data* td = (Thread_Data*)args;
//     td->_ptsvr->Service1(td->_new_socket, td->_client_ip, td->_client_port);

//     delete td;
//     return nullptr;
// }


//4.0线程池版本
//预先创建一批线程 + 限制线程的个数
//每来一个连接 就当作是一个任务--push进任务队列--等待线程来处理




